#ifndef AFCORE_COMMON_LOG_APPENDER_APPENDER_FILE_DAILY_
#define AFCORE_COMMON_LOG_APPENDER_APPENDER_FILE_DAILY_

#include "logcommon.h"
#include "helper.h"
#include "helper_file.h"
#include "appender_base.h"
#include "sync.h"
#include "circular_queue.h"

namespace afcore {

/// @brief  日志
namespace log {

/// @brief  每日文件追加器日期计算辅助类
struct SAppenderFileDailyCalc {
  /// @brief  计算文件名的时间
  /// @param  filename        文件名
  /// @param  now_tm          当前时间结构
  /// @return 带时间日期的文件名
  static RFileName CalcFilename(const RFileName& filename, const tm& now_tm) {
    RFileName basename;
    RFileName ext;
    std::tie(basename, ext) = CHelperFile::SplitByExtension(filename);
    return fmt::format("{}_{:04d}-{:02d}-{:02d}{}", basename, now_tm.tm_year + 1900, now_tm.tm_mon + 1, now_tm.tm_mday, ext);
  }
};

/// @brief  每日文件追加器
/// @tparam Mutex       互斥锁
template<typename Mutex, typename FileNameCalc = SAppenderFileDailyCalc>
class CAppenderFileDaily final
  : public CAppenderBase<Mutex> {
public:
  /// @brief  构造函数 显示
  /// @param  base_filename       日志文件名
  /// @param  rotation_hour       轮转小时
  /// @param  rotation_minute     轮转分钟
  /// @param  truncate            是否截断 如果false != truncate 新创建的文件将被截断
  /// @param  max_files           最大的文件数量 如果max_files > 0 那么超过max_files后，最先创建的文件会被删除
  explicit CAppenderFileDaily(RFileName base_filename, int rotation_hour, int rotation_minute, bool truncate = false, uint16_t max_files = 0);
  /// @brief  获取文件名
  /// @return 文件名
  RFileName FileName();
protected:
  /// @brief  记录 子类实现
  /// @param  msg         日志信息
  void DoLog(const SLogMessage& msg) override;
  /// @brief  刷新 子类实现
  void DoFlush() override;
private:
  /// @brief  初始化文件名队列
  void InitFileNameQueue();
  /// @brief  获取当前时间结构体
  /// @retun  当前时间结构体
  tm NowTm(RClockLog::time_point tp);
  /// @brief  获取下次轮转时间点
  /// @return 下次轮转时间点
  RClockLog::time_point NextRotationTp();
  /// @brief  删除最老的文件
  void DeleteOld();
private:
  RFileName base_filename_;               ///< 文件基本名
  int rotation_h_ {0};                    ///< 轮转小时
  int rotation_m_ {0};                    ///< 轮转分钟
  RClockLog::time_point rotation_tp_;     ///< 轮转时间点
  CHelperFile helper_file_;               ///< 文件帮助类
  bool truncate_ {false};                 ///< 是否截断标识
  uint16_t max_files_ {0};                ///< 最大文件数量
  CCircularQueue<RFileName> filename_q_;  ///< 文件名循环队列
};

using RAppenderFileDaily_MT = CAppenderFileDaily<std::mutex>;
using RAppenderFileDaily_ST = CAppenderFileDaily<SNullMutex>;

} // !namespace log

using namespace log;

template<typename Factory = SSyncFactory>
std::shared_ptr<CLogger> FileDaily_MT(const std::string& logger_name,
  const RFileName& filename,
  int hour = 0,
  int minute = 0,
  bool truncate = false,
  uint16_t max_files = 0);

template<typename Factory = SSyncFactory>
std::shared_ptr<CLogger> FileDaily_ST(const std::string& logger_name,
  const RFileName& filename,
  int hour = 0,
  int minute = 0,
  bool truncate = false,
  uint16_t max_files = 0);

} // !namespace afcore

#endif //! AFCORE_COMMON_LOG_APPENDER_APPENDER_FILE_DAILY_